﻿// Copyright (c) 2012 Mokah Nnamezie & Andrew Cooper
// Neo4Net graph database - http://neo4net.codeplex.com
//
// This file is part of Neo4Net - a .Net port of the Neo4j graph database
//
// Neo4Net is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace Neo4Net.Kernel.Impl.Core
{
    using System;
    using System.IO;
    using Neo4Net.GraphDb;
    using Neo4Net.GraphDb.Factory;
    using NUnit.Framework;

    [TestFixture]
    public class TestExceptionTypeOnInvalidIds
    {
        private static readonly long smallPositiveInteger = 5;
        private static readonly long smallNegativeInteger = -5;
        private static readonly long bigPositiveInteger = Int32.MaxValue;
        private static readonly long bigNegativeInteger = Int32.MinValue;
        private static readonly long smallPositiveLong = ((long)Int32.MaxValue) + 1;
        private static readonly long smallNegativeLong = -((long)Int32.MinValue) - 1;
        private static readonly long bigPositiveLong = Int64.MaxValue;
        private static readonly long bigNegativeLong = Int64.MinValue;
        private static IGraphDatabaseService graphdb;
        private static IGraphDatabaseService graphDbReadOnly;
        private ITransaction tx;

        [TestFixtureSetUp]
        public static void CreateDatabase()
        {
            String storeDir = "target/var/id_test";
            AbstractNeo4NetTestCase.DeleteFileOrDirectory(new DirectoryInfo(storeDir));
            graphdb = new GraphDatabaseFactory().NewEmbeddedDatabase(storeDir);
            graphDbReadOnly = new GraphDatabaseFactory().NewEmbeddedDatabaseBuilder(storeDir)
                                                        .SetConfig(GraphDatabaseSettings.ReadOnly, GraphDatabaseSetting.True)
                                                        .NewGraphDatabase();
        }

        [TestFixtureTearDown]
        public static void DestroyDatabase()
        {
            graphDbReadOnly.Shutdown();
            graphDbReadOnly = null;
            graphdb.Shutdown();
            graphdb = null;
        }

        [SetUp]
        public void StartTransaction()
        {
            tx = graphdb.BeginTx();
        }

        [TearDown]
        public void EndTransaction()
        {
            tx.Finish();
            tx = null;
        }

        /* behaves as expected */
        [Test]
        public void GetNodeBySmallPossitiveInteger()
        {
            Assert.That(() => GetNodeById(smallPositiveInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(smallPositiveInteger), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetNodeBySmallNegativeInteger()
        {
            Assert.That(() => GetNodeById(smallNegativeInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(smallNegativeInteger), Throws.TypeOf<NotFoundException>());
        }

        /* behaves as expected */
        [Test]
        public void GetNodeByBigPossitiveInteger()
        {
            Assert.That(() => GetNodeById(bigPositiveInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(bigPositiveInteger), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetNodeByBigNegativeInteger()
        {
            Assert.That(() => GetNodeById(bigNegativeInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(bigNegativeInteger), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetNodeBySmallPossitiveLong()
        {
            Assert.That(() => GetNodeById(smallPositiveLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(smallPositiveLong), Throws.TypeOf<NotFoundException>());
        }

        /* behaves as expected */
        [Test]
        public void GetNodeBySmallNegativeLong()
        {
            Assert.That(() => GetNodeById(smallNegativeLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(smallNegativeLong), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetNodeByBigPossitiveLong()
        {
            Assert.That(() => GetNodeById(bigPositiveLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(bigPositiveLong), Throws.TypeOf<NotFoundException>());
        }

        /* finds the node with id=0, since that what the id truncates to */
        [Test]
        public void GetNodeByBigNegativeLong()
        {
            Assert.That(() => GetNodeById(bigNegativeLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetNodeByIdReadOnly(bigNegativeLong), Throws.TypeOf<NotFoundException>());
        }

        /* behaves as expected */
        [Test]
        public void GetRelationshipBySmallPossitiveInteger()
        {
            Assert.That(() => GetRelationshipById(smallPositiveInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(smallPositiveInteger), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetRelationshipBySmallNegativeInteger()
        {
            Assert.That(() => GetRelationshipById(smallNegativeInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(smallPositiveInteger), Throws.TypeOf<NotFoundException>());
        }

        /* behaves as expected */
        [Test]
        public void GetRelationshipByBigPossitiveInteger()
        {
            Assert.That(() => GetRelationshipById(bigPositiveInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(bigPositiveInteger), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetRelationshipByBigNegativeInteger()
        {
            Assert.That(() => GetRelationshipById(bigNegativeInteger), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(bigNegativeInteger), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetRelationshipBySmallPossitiveLong()
        {
            Assert.That(() => GetRelationshipById(smallPositiveLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(smallPositiveLong), Throws.TypeOf<NotFoundException>());
        }

        /* behaves as expected */
        [Test]
        public void GetRelationshipBySmallNegativeLong()
        {
            Assert.That(() => GetRelationshipById(smallNegativeLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(smallNegativeLong), Throws.TypeOf<NotFoundException>());
        }

        /* throws IllegalArgumentException instead of NotFoundException */
        [Test]
        public void GetRelationshipByBigPossitiveLong()
        {
            Assert.That(() => GetRelationshipById(bigPositiveLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(bigPositiveLong), Throws.TypeOf<NotFoundException>());
        }

        /* behaves as expected */
        [Test]
        public void GetRelationshipByBigNegativeLong()
        {
            Assert.That(() => GetRelationshipById(bigNegativeLong), Throws.TypeOf<NotFoundException>());
            Assert.That(() => GetRelationshipByIdReadOnly(bigNegativeLong), Throws.TypeOf<NotFoundException>());
        }

        private void GetNodeById(long index)
        {
            INode value = graphdb.GetNodeById(index);
            Assert.Fail("Returned Node [0x{0:x}] for index 0x{1:x} (int value: 0x{2:x})", value.Id, index, (int)index);
        }

        private void GetNodeByIdReadOnly(long index)
        {
            INode value = graphDbReadOnly.GetNodeById(index);
            Assert.Fail("Returned Node [0x{0:x}] for index 0x{1:x} (int value: 0x{2:x})", value.Id, index, (int)index);
        }

        private void GetRelationshipById(long index)
        {
            IRelationship value = graphdb.GetRelationshipById(index);
            Assert.Fail("Returned Relationship [0x{0:x}] for index 0x{1:x} (int value: 0x{2:x})", value.Id, index, (int)index);
        }

        private void GetRelationshipByIdReadOnly(long index)
        {
            IRelationship value = graphDbReadOnly.GetRelationshipById(index);
            Assert.Fail("Returned Relationship [0x{0:x}] for index 0x{1:x} (int value: 0x{2:x})", value.Id, index, (int)index);
        }
    }
}
